/*    $OpenBSD: if_wpireg.h,v 1.28 2013/11/26 20:33:17 deraadt Exp $    */

/*-
 * Copyright (c) 2006-2008
 *    Damien Bergamini <damien.bergamini@free.fr>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#define WPI_TX_RING_COUNT    256
#define WPI_TX_RING_LOMARK    192
#define WPI_TX_RING_HIMARK    224
#define WPI_RX_RING_COUNT_LOG    6
#define WPI_RX_RING_COUNT    (1 << WPI_RX_RING_COUNT_LOG)

#define WPI_NTXQUEUES        8
#define WPI_NDMACHNLS        6

/* Maximum scatter/gather. */
#define WPI_MAX_SCATTER    4

/* Maximum RX buffer size (larger than MCLBYTES.) */
#define WPI_RBUF_SIZE    (3 * 1024)

/* Base Address Register. */
#define WPI_PCI_BAR0    PCI_MAPREG_START

/*
 * Control and status registers.
 */
#define WPI_HW_IF_CONFIG    0x000
#define WPI_INT            0x008
#define WPI_MASK        0x00c
#define WPI_FH_INT        0x010
#define WPI_GPIO_IN        0x018
#define WPI_RESET        0x020
#define WPI_GP_CNTRL        0x024
#define WPI_EEPROM        0x02c
#define WPI_EEPROM_GP        0x030
#define WPI_UCODE_GP1_CLR    0x05c
#define WPI_UCODE_GP2        0x060
#define WPI_GIO_CHICKEN        0x100
#define WPI_ANA_PLL        0x20c
#define WPI_MEM_RADDR        0x40c
#define WPI_MEM_WADDR        0x410
#define WPI_MEM_WDATA        0x418
#define WPI_MEM_RDATA        0x41c
#define WPI_PRPH_WADDR        0x444
#define WPI_PRPH_RADDR        0x448
#define WPI_PRPH_WDATA        0x44c
#define WPI_PRPH_RDATA        0x450
#define WPI_HBUS_TARG_WRPTR    0x460
#define WPI_FH_CBBC_CTRL(qid)    (0x940 + (qid) * 8)
#define WPI_FH_CBBC_BASE(qid)    (0x944 + (qid) * 8)
#define WPI_FH_RX_CONFIG    0xc00
#define WPI_FH_RX_BASE        0xc04
#define WPI_FH_RX_WPTR        0xc20
#define WPI_FH_RX_RPTR_ADDR    0xc24
#define WPI_FH_RSSR_TBL        0xcc0
#define WPI_FH_RX_STATUS    0xcc4
#define WPI_FH_TX_CONFIG(qid)    (0xd00 + (qid) * 32)
#define WPI_FH_TX_BASE        0xe80
#define WPI_FH_MSG_CONFIG    0xe88
#define WPI_FH_TX_STATUS    0xe90


/*
 * NIC internal memory offsets.
 */
#define WPI_ALM_SCHED_MODE        0x2e00
#define WPI_ALM_SCHED_ARASTAT        0x2e04
#define WPI_ALM_SCHED_TXFACT        0x2e10
#define WPI_ALM_SCHED_TXF4MF        0x2e14
#define WPI_ALM_SCHED_TXF5MF        0x2e20
#define WPI_ALM_SCHED_SBYPASS_MODE1    0x2e2c
#define WPI_ALM_SCHED_SBYPASS_MODE2    0x2e30
#define WPI_APMG_CLK_ENA        0x3004
#define WPI_APMG_CLK_DIS        0x3008
#define WPI_APMG_RFKILL            0x3014
#define WPI_APMG_PS            0x300c
#define WPI_APMG_PCI_STT        0x3010
#define WPI_BSM_WR_CTRL            0x3400
#define WPI_BSM_WR_MEM_SRC        0x3404
#define WPI_BSM_WR_MEM_DST        0x3408
#define WPI_BSM_WR_DWCOUNT        0x340c
#define WPI_BSM_SRAM_BASE        0x3800
#define WPI_BSM_DRAM_TEXT_ADDR        0x3490
#define WPI_BSM_DRAM_TEXT_SIZE        0x3494
#define WPI_BSM_DRAM_DATA_ADDR        0x3498
#define WPI_BSM_DRAM_DATA_SIZE        0x349c


/* Possible flags for register WPI_HW_IF_CONFIG. */
#define WPI_HW_IF_CONFIG_ALM_MB        (1 << 8)
#define WPI_HW_IF_CONFIG_ALM_MM        (1 << 9)
#define WPI_HW_IF_CONFIG_SKU_MRC    (1 << 10)
#define WPI_HW_IF_CONFIG_REV_D        (1 << 11)
#define WPI_HW_IF_CONFIG_TYPE_B        (1 << 12)

/* Possible flags for registers WPI_PRPH_RADDR/WPI_PRPH_WADDR. */
#define WPI_PRPH_DWORD    ((sizeof (uint32_t) - 1) << 24)

/* Possible values for WPI_BSM_WR_MEM_DST. */
#define WPI_FW_TEXT_BASE    0x00000000
#define WPI_FW_DATA_BASE    0x00800000

/* Possible flags for WPI_GPIO_IN. */
#define WPI_GPIO_IN_VMAIN    (1 << 9)

/* Possible flags for register WPI_RESET. */
#define WPI_RESET_NEVO            (1 << 0)
#define WPI_RESET_SW            (1 << 7)
#define WPI_RESET_MASTER_DISABLED    (1 << 8)
#define WPI_RESET_STOP_MASTER        (1 << 9)

/* Possible flags for register WPI_GP_CNTRL. */
#define WPI_GP_CNTRL_MAC_CLOCK_READY    (1 <<  0)
#define WPI_GP_CNTRL_MAC_ACCESS_ENA    (1 <<  0)
#define WPI_GP_CNTRL_INIT_DONE        (1 <<  2)
#define WPI_GP_CNTRL_MAC_ACCESS_REQ    (1 <<  3)
#define WPI_GP_CNTRL_SLEEP        (1 <<  4)
#define WPI_GP_CNTRL_PS_MASK        (7 << 24)
#define WPI_GP_CNTRL_MAC_PS        (4 << 24)
#define WPI_GP_CNTRL_RFKILL        (1 << 27)

/* Possible flags for register WPI_GIO_CHICKEN. */
#define WPI_GIO_CHICKEN_L1A_NO_L0S_RX    (1 << 23)

/* Possible flags for register WPI_FH_RX_CONFIG. */
#define WPI_FH_RX_CONFIG_DMA_ENA        (1U << 31)
#define WPI_FH_RX_CONFIG_RDRBD_ENA        (1U << 29)
#define WPI_FH_RX_CONFIG_WRSTATUS_ENA        (1U << 27)
#define WPI_FH_RX_CONFIG_MAXFRAG        (1U << 24)
#define WPI_FH_RX_CONFIG_NRBD(x)        ((x) << 20)
#define WPI_FH_RX_CONFIG_IRQ_DST_HOST        (1U << 12)
#define WPI_FH_RX_CONFIG_IRQ_RBTH(x)        ((x) << 4)

/* Possible flags for register WPI_ANA_PLL. */
#define WPI_ANA_PLL_INIT    (1 << 24)

/* Possible flags for register WPI_UCODE_GP1_CLR. */
#define WPI_UCODE_GP1_RFKILL        (1 << 1)
#define WPI_UCODE_GP1_CMD_BLOCKED    (1 << 2)

/* Possible flags for WPI_FH_RX_STATUS. */
#define    WPI_FH_RX_STATUS_IDLE    (1 << 24)

/* Possible flags for register WPI_BSM_WR_CTRL. */
#define WPI_BSM_WR_CTRL_START_EN    (1U << 30)
#define WPI_BSM_WR_CTRL_START        (1U << 31)

/* Possible flags for register WPI_INT. */
#define WPI_INT_ALIVE        (1U <<  0)
#define WPI_INT_WAKEUP        (1U <<  1)
#define WPI_INT_SW_RX        (1U <<  3)
#define WPI_INT_RF_TOGGLED    (1U <<  7)
#define WPI_INT_SW_ERR        (1U << 25)
#define WPI_INT_FH_TX        (1U << 27)
#define WPI_INT_HW_ERR        (1U << 29)
#define WPI_INT_FH_RX        (1U << 31)

/* Shortcut. */
#define WPI_INT_MASK                            \
    (WPI_INT_SW_ERR | WPI_INT_HW_ERR | WPI_INT_FH_TX |         \
     WPI_INT_FH_RX | WPI_INT_ALIVE | WPI_INT_WAKEUP |        \
     WPI_INT_SW_RX | WPI_INT_RF_TOGGLED)

/* Possible flags for register WPI_FH_INT. */
#define WPI_FH_INT_RX_CHNL(x)    (1 << ((x) + 16))
#define WPI_FH_INT_HI_PRIOR    (1 << 30)
/* Shortcuts for the above. */
#define WPI_FH_INT_RX            \
    (WPI_FH_INT_RX_CHNL(0) |    \
     WPI_FH_INT_RX_CHNL(1) |    \
     WPI_FH_INT_RX_CHNL(2) |    \
     WPI_FH_INT_HI_PRIOR)

/* Possible flags for register WPI_FH_TX_STATUS. */
#define WPI_FH_TX_STATUS_IDLE(qid)    \
    (1 << ((qid) + 24) | 1 << ((qid) + 16))

/* Possible flags for register WPI_EEPROM. */
#define WPI_EEPROM_READ_VALID    (1 << 0)
#define WPI_EEPROM_CMD        (1 << 1)

/* Possible flags for register WPI_EEPROM_GP. */
#define WPI_EEPROM_GP_IF_OWNER    0x00000180

/* Possible flags for register WPI_APMG_PS. */
#define WPI_APMG_PS_PWR_SRC_MASK    (3 << 24)

/* Possible flags for register WPI_APMG_CLK_ENA/WPI_APMG_CLK_DIS. */
#define WPI_APMG_CLK_DMA_CLK_RQT    (1 <<  9)
#define WPI_APMG_CLK_BSM_CLK_RQT    (1 << 11)

/* Possible flags for register WPI_APMG_PCI_STT. */
#define WPI_APMG_PCI_STT_L1A_DIS    (1 << 11)

struct wpi_shared {
    uint32_t    txbase[8];
    uint32_t    next;
    uint32_t    reserved[2];
} __packed;

#define WPI_MAX_SEG_LEN    65520
struct wpi_tx_desc {
    uint32_t    flags;
#define WPI_PAD32(x)    ((((x) + 3) & ~3) - (x))

    struct {
        uint32_t    addr;
        uint32_t    len;
    } __packed    segs[WPI_MAX_SCATTER];
    uint8_t        reserved[28];
} __packed;

struct wpi_tx_stat {
    uint8_t        nrts;
    uint8_t        retrycnt;
    uint8_t        nkill;
    uint8_t        rate;
    uint32_t    duration;
    uint32_t    status;
} __packed;

struct wpi_rx_desc {
    uint32_t    len;
    uint8_t        type;
#define WPI_UC_READY          1
#define WPI_ADD_NODE_DONE     24
#define WPI_RX_DONE         27
#define WPI_TX_DONE         28
#define WPI_START_SCAN        130
#define WPI_STOP_SCAN        132
#define WPI_STATE_CHANGED    161

    uint8_t        flags;
    uint8_t        idx;
    uint8_t        qid;
} __packed;

struct wpi_tx_cmd {
    uint8_t    code;
#define WPI_CMD_RXON         16
#define WPI_CMD_ASSOCIATE     17
#define WPI_CMD_EDCA_PARAMS     19
#define WPI_CMD_TIMING         20
#define WPI_CMD_ADD_NODE     24
#define WPI_CMD_TX_DATA         28
#define WPI_CMD_MRR_SETUP     71
#define WPI_CMD_SET_LED         72
#define WPI_CMD_SET_POWER_MODE    119
#define WPI_CMD_SCAN        128
#define WPI_CMD_TXPOWER        151
#define WPI_CMD_BT_COEX        155

    uint8_t    flags;
    uint8_t    idx;
    uint8_t    qid;
    uint8_t    data[124];
} __packed;

/* Structure for command WPI_CMD_RXON. */
struct wpi_rxon {
    uint8_t        myaddr[IEEE80211_ADDR_LEN];
    uint16_t    reserved1;
    uint8_t        bssid[IEEE80211_ADDR_LEN];
    uint16_t    reserved2;
    uint32_t    reserved3[2];
    uint8_t        mode;
#define WPI_MODE_HOSTAP        1
#define WPI_MODE_STA        3
#define WPI_MODE_IBSS        4
#define WPI_MODE_MONITOR    6

    uint8_t        reserved4[3];
    uint8_t        ofdm_mask;
    uint8_t        cck_mask;
    uint16_t    associd;
    uint32_t    flags;
#define WPI_RXON_24GHZ        (1 <<  0)
#define WPI_RXON_CCK        (1 <<  1)
#define WPI_RXON_AUTO        (1 <<  2)
#define WPI_RXON_SHSLOT        (1 <<  4)
#define WPI_RXON_SHPREAMBLE    (1 <<  5)
#define WPI_RXON_NODIVERSITY    (1 <<  7)
#define WPI_RXON_ANT_A        (1 <<  8)
#define WPI_RXON_ANT_B        (1 <<  9)
#define WPI_RXON_TSF        (1 << 15)

    uint32_t    filter;
#define WPI_FILTER_PROMISC    (1 << 0)
#define WPI_FILTER_CTL        (1 << 1)
#define WPI_FILTER_MULTICAST    (1 << 2)
#define WPI_FILTER_NODECRYPT    (1 << 3)
#define WPI_FILTER_BSS        (1 << 5)

    uint8_t        chan;
    uint8_t        reserved6[3];
} __packed;

/* Structure for command WPI_CMD_ASSOCIATE. */
struct wpi_assoc {
    uint32_t    flags;
    uint32_t    filter;
    uint8_t        ofdm_mask;
    uint8_t        cck_mask;
    uint16_t    reserved;
} __packed;

/* Structure for command WPI_CMD_EDCA_PARAMS. */
struct wpi_edca_params {
    uint32_t    flags;
#define WPI_EDCA_UPDATE    (1 << 0)
#define WPI_EDCA_TXOP    (1 << 4)

    struct {
        uint16_t    cwmin;
        uint16_t    cwmax;
        uint8_t        aifsn;
        uint8_t        reserved;
        uint16_t    txoplimit;
    } __packed    ac[EDCA_NUM_AC];
} __packed;

/* Structure for command WPI_CMD_TIMING. */
struct wpi_cmd_timing {
    uint64_t    tstamp;
    uint16_t    bintval;
    uint16_t    atim;
    uint32_t    binitval;
    uint16_t    lintval;
    uint16_t    reserved;
} __packed;

/* Structure for command WPI_CMD_ADD_NODE. */
struct wpi_node_info {
    uint8_t        control;
#define WPI_NODE_UPDATE        (1 << 0)

    uint8_t        reserved1[3];
    uint8_t        macaddr[IEEE80211_ADDR_LEN];
    uint16_t    reserved2;
    uint8_t        id;
#define WPI_ID_BSS        0
#define WPI_ID_BROADCAST    24

    uint8_t        flags;
#define WPI_FLAG_SET_KEY    (1 << 0)

    uint16_t    reserved3;
    uint16_t    kflags;
#define WPI_KFLAG_CCMP        (1 <<  1)
#define WPI_KFLAG_KID(kid)    ((kid) << 8)

    uint8_t        tsc2;
    uint8_t        reserved4;
    uint16_t    ttak[5];
    uint16_t    reserved5;
    uint8_t        key[16];

    uint32_t    action;
#define WPI_ACTION_SET_RATE    (1 << 2)

    uint32_t    mask;
    uint16_t    tid;
    uint8_t        plcp;
    uint8_t        antenna;
#define WPI_ANTENNA_A        (1 << 6)
#define WPI_ANTENNA_B        (1 << 7)
#define WPI_ANTENNA_BOTH    (WPI_ANTENNA_A | WPI_ANTENNA_B)

    uint8_t        add_imm;
    uint8_t        del_imm;
    uint16_t    add_imm_start;
} __packed;

/* Structure for command WPI_CMD_TX_DATA. */
struct wpi_cmd_data {
    uint16_t    len;
    uint16_t    lnext;
    uint32_t    flags;
#define WPI_TX_NEED_RTS        (1 <<  1)
#define WPI_TX_NEED_CTS        (1 <<  2)
#define WPI_TX_NEED_ACK        (1 <<  3)
#define WPI_TX_FULL_TXOP    (1 <<  7)
#define WPI_TX_BT_DISABLE    (1 << 12)    /* bluetooth coexistence */
#define WPI_TX_AUTO_SEQ        (1 << 13)
#define WPI_TX_INSERT_TSTAMP    (1 << 16)

    uint8_t        plcp;
    uint8_t        id;
    uint8_t        tid;
    uint8_t        security;
#define WPI_CIPHER_WEP40    1
#define WPI_CIPHER_CCMP        2
#define WPI_CIPHER_TKIP        3
#define WPI_CIPHER_WEP104    9

    uint8_t        key[IEEE80211_KEYBUF_SIZE];
    uint8_t        tkip[IEEE80211_TKIP_MICLEN];
    uint32_t    fnext;
    uint32_t    lifetime;
#define WPI_LIFETIME_INFINITE    0xffffffff

    uint8_t        ofdm_mask;
    uint8_t        cck_mask;
    uint8_t        rts_ntries;
    uint8_t        data_ntries;
    uint16_t    timeout;
    uint16_t    txop;
} __packed;

/* Structure for command WPI_CMD_MRR_SETUP. */
#define WPI_RIDX_MAX    11
struct wpi_mrr_setup {
    uint32_t    which;
#define WPI_MRR_CTL    0
#define WPI_MRR_DATA    1

    struct {
        uint8_t    plcp;
        uint8_t    flags;
        uint8_t    ntries;
        uint8_t    next;
    } __packed    rates[WPI_RIDX_MAX + 1];
} __packed;

/* Structure for command WPI_CMD_SET_LED. */
struct wpi_cmd_led {
    uint32_t    unit;    /* multiplier (in usecs) */
    uint8_t        which;
#define WPI_LED_ACTIVITY    1
#define WPI_LED_LINK        2

    uint8_t        off;
    uint8_t        on;
    uint8_t        reserved;
} __packed;

/* Structure for command WPI_CMD_SET_POWER_MODE. */
struct wpi_pmgt_cmd {
    uint32_t    flags;
#define WPI_PS_ALLOW_SLEEP    (1 << 0)
#define WPI_PS_SLEEP_OVER_DTIM    (1 << 2)
#define WPI_PS_PCI_PMGT        (1 << 3)

    uint32_t    rxtimeout;
    uint32_t    txtimeout;
    uint32_t    intval[5];
} __packed;

/* Structures for command WPI_CMD_SCAN. */
struct wpi_scan_essid {
    uint8_t    id;
    uint8_t    len;
    uint8_t    data[IEEE80211_NWID_LEN];
} __packed;

struct wpi_scan_hdr {
    uint16_t    len;
    uint8_t        reserved1;
    uint8_t        nchan;
    uint16_t    quiet_time;
    uint16_t    quiet_threshold;
    uint16_t    crc_threshold;
    uint16_t    reserved2;
    uint32_t    max_svc;    /* background scans */
    uint32_t    pause_svc;    /* background scans */
    uint32_t    flags;
    uint32_t    filter;

    /* Followed by a struct wpi_cmd_data. */
    /* Followed by an array of 4 structq wpi_scan_essid. */
    /* Followed by probe request body. */
    /* Followed by an array of ``nchan'' structs wpi_scan_chan. */
} __packed;

struct wpi_scan_chan {
    uint8_t        flags;
#define WPI_CHAN_ACTIVE        (1 << 0)
#define WPI_CHAN_NPBREQS(x)    (((1 << (x)) - 1) << 1)

    uint8_t        chan;
    uint8_t        rf_gain;
    uint8_t        dsp_gain;
    uint16_t    active;        /* msecs */
    uint16_t    passive;    /* msecs */
} __packed;

/* Maximum size of a scan command. */
#define WPI_SCAN_MAXSZ    (MCLBYTES - 4)

/* Structure for command WPI_CMD_TXPOWER. */
struct wpi_cmd_txpower {
    uint8_t        band;
#define WPI_BAND_5GHZ    0
#define WPI_BAND_2GHZ    1

    uint8_t        reserved;
    uint16_t    chan;
    struct {
        uint8_t    plcp;
        uint8_t    rf_gain;
        uint8_t    dsp_gain;
        uint8_t    reserved;
    } __packed    rates[WPI_RIDX_MAX + 1];
} __packed;

/* Structure for command WPI_CMD_BT_COEX. */
struct wpi_bluetooth {
    uint8_t        flags;
#define WPI_BT_COEX_DISABLE    0
#define WPI_BT_COEX_MODE_2WIRE    1
#define WPI_BT_COEX_MODE_3WIRE    2
#define WPI_BT_COEX_MODE_4WIRE    3

    uint8_t        lead_time;
#define WPI_BT_LEAD_TIME_DEF    30

    uint8_t        max_kill;
#define WPI_BT_MAX_KILL_DEF    5

    uint8_t        reserved;
    uint32_t    kill_ack;
    uint32_t    kill_cts;
} __packed;

/* Structures for WPI_RX_DONE notification. */
struct wpi_rx_stat {
    uint8_t        len;
#define WPI_STAT_MAXLEN    20

    uint8_t        id;
    uint8_t        rssi;    /* received signal strength */
#define WPI_RSSI_OFFSET    95

    uint8_t        agc;    /* access gain control */
    uint16_t    signal;
    uint16_t    noise;
} __packed;

struct wpi_rx_head {
    uint16_t    chan;
    uint16_t    flags;
    uint8_t        reserved;
    uint8_t        rate;
    uint16_t    len;
} __packed;

struct wpi_rx_tail {
    uint32_t    flags;
#define WPI_RX_NO_CRC_ERR    (1 <<  0)
#define WPI_RX_NO_OVFL_ERR    (1 <<  1)
/* Shortcut for the above. */
#define WPI_RX_NOERROR        (WPI_RX_NO_CRC_ERR | WPI_RX_NO_OVFL_ERR)
#define WPI_RX_CIPHER_MASK    (7 <<  8)
#define WPI_RX_CIPHER_CCMP    (2 <<  8)
#define WPI_RX_DECRYPT_MASK    (3 << 11)
#define WPI_RX_DECRYPT_OK    (3 << 11)

    uint64_t    tstamp;
    uint32_t    tbeacon;
} __packed;

/* Structure for WPI_UC_READY notification. */
struct wpi_ucode_info {
    uint32_t    version;
    uint8_t        revision[8];
    uint8_t        type;
    uint8_t        subtype;
#define WPI_UCODE_INIT    9

    uint16_t    reserved;
    uint32_t    logptr;
    uint32_t    errptr;
    uint32_t    timestamp;
    uint32_t    valid;
} __packed;

/* Structure for WPI_START_SCAN notification. */
struct wpi_start_scan {
    uint64_t    tstamp;
    uint32_t    tbeacon;
    uint8_t        chan;
    uint8_t        band;
    uint16_t    reserved;
    uint32_t    status;
} __packed;

/* Structure for WPI_STOP_SCAN notification. */
struct wpi_stop_scan {
    uint8_t        nchan;
    uint8_t        status;
    uint8_t        reserved;
    uint8_t        chan;
    uint64_t    tsf;
} __packed;


/* Firmware error dump entry. */
struct wpi_fwdump {
    uint32_t    desc;
    uint32_t    time;
    uint32_t    blink[2];
    uint32_t    ilink[2];
    uint32_t    data;
} __packed;

/* Firmware image file header. */
struct wpi_firmware_hdr {
    uint32_t    version;
    uint32_t    main_textsz;
    uint32_t    main_datasz;
    uint32_t    init_textsz;
    uint32_t    init_datasz;
    uint32_t    boot_textsz;
} __packed;

#define WPI_FW_TEXT_MAXSZ    (80 * 1024)
#define WPI_FW_DATA_MAXSZ    (32 * 1024)
#define WPI_FW_BOOT_TEXT_MAXSZ    1024

#define WPI_FW_UPDATED    (1U << 31)

/*
 * Offsets into EEPROM.
 */
#define WPI_EEPROM_MAC        0x015
#define WPI_EEPROM_REVISION    0x035
#define WPI_EEPROM_CAPABILITIES    0x045
#define WPI_EEPROM_TYPE        0x04a
#define WPI_EEPROM_DOMAIN    0x060
#define WPI_EEPROM_BAND1    0x063
#define WPI_EEPROM_BAND2    0x072
#define WPI_EEPROM_BAND3    0x080
#define WPI_EEPROM_BAND4    0x08d
#define WPI_EEPROM_BAND5    0x099
#define WPI_EEPROM_POWER_GRP    0x100

struct wpi_eeprom_chan {
    uint8_t    flags;
#define WPI_EEPROM_CHAN_VALID    (1 << 0)
#define WPI_EEPROM_CHAN_IBSS    (1 << 1)
#define WPI_EEPROM_CHAN_ACTIVE    (1 << 3)
#define WPI_EEPROM_CHAN_RADAR    (1 << 4)

    int8_t    maxpwr;
} __packed;

struct wpi_eeprom_sample {
    uint8_t        index;
    int8_t        power;
    uint16_t    volt;
} __packed;

#define WPI_POWER_GROUPS_COUNT    5
struct wpi_eeprom_group {
    struct        wpi_eeprom_sample samples[5];
    int32_t        coef[5];
    int32_t        corr[5];
    int8_t        maxpwr;
    uint8_t        chan;
    int16_t        temp;
} __packed;

#define WPI_CHAN_BANDS_COUNT    5
#define WPI_MAX_CHAN_PER_BAND    14
static const struct wpi_chan_band {
    uint32_t    addr;    /* offset in EEPROM */
    uint8_t        nchan;
    uint8_t        chan[WPI_MAX_CHAN_PER_BAND];
} wpi_bands[5] = {
    { WPI_EEPROM_BAND1, 14,
        { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 } },
    { WPI_EEPROM_BAND2, 13,
        { 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16 } },
    { WPI_EEPROM_BAND3, 12,
        { 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 } },
    { WPI_EEPROM_BAND4, 11,
        { 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 } },
    { WPI_EEPROM_BAND5, 6,
        { 145, 149, 153, 157, 161, 165 } }
};

/* HW rate indices. */
#define WPI_RIDX_OFDM6     0
#define WPI_RIDX_OFDM36     5
#define WPI_RIDX_OFDM48     6
#define WPI_RIDX_OFDM54     7
#define WPI_RIDX_CCK1     8
#define WPI_RIDX_CCK2     9
#define WPI_RIDX_CCK11    11

static const struct wpi_rate {
    uint8_t    rate;
    uint8_t    plcp;
} wpi_rates[WPI_RIDX_MAX + 1] = {
    {  12, 0xd },
    {  18, 0xf },
    {  24, 0x5 },
    {  36, 0x7 },
    {  48, 0x9 },
    {  72, 0xb },
    {  96, 0x1 },
    { 108, 0x3 },
    {   2,  10 },
    {   4,  20 },
    {  11,  55 },
    {  22, 110 }
};

#define WPI_MAX_PWR_INDEX    77
/*
 * RF Tx gain values from highest to lowest power (values obtained from
 * the reference driver.)
 */
static const uint8_t wpi_rf_gain_2ghz[WPI_MAX_PWR_INDEX + 1] = {
    0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xbb, 0xbb, 0xbb,
    0xbb, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xd3, 0xd3, 0xb3, 0xb3, 0xb3,
    0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x73, 0xeb, 0xeb, 0xeb,
    0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xab, 0xab, 0xab, 0x8b,
    0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xc3, 0xc3, 0xc3, 0xc3, 0xa3,
    0xa3, 0xa3, 0xa3, 0x83, 0x83, 0x83, 0x83, 0x63, 0x63, 0x63, 0x63,
    0x43, 0x43, 0x43, 0x43, 0x23, 0x23, 0x23, 0x23, 0x03, 0x03, 0x03,
    0x03
};

static const uint8_t wpi_rf_gain_5ghz[WPI_MAX_PWR_INDEX + 1] = {
    0xfb, 0xfb, 0xfb, 0xdb, 0xdb, 0xbb, 0xbb, 0x9b, 0x9b, 0x7b, 0x7b,
    0x7b, 0x7b, 0x5b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x1b, 0x1b,
    0x1b, 0x73, 0x73, 0x73, 0x53, 0x53, 0x53, 0x53, 0x53, 0x33, 0x33,
    0x33, 0x33, 0x13, 0x13, 0x13, 0x13, 0x13, 0xab, 0xab, 0xab, 0x8b,
    0x8b, 0x8b, 0x8b, 0x6b, 0x6b, 0x6b, 0x6b, 0x4b, 0x4b, 0x4b, 0x4b,
    0x2b, 0x2b, 0x2b, 0x2b, 0x0b, 0x0b, 0x0b, 0x0b, 0x83, 0x83, 0x63,
    0x63, 0x63, 0x63, 0x43, 0x43, 0x43, 0x43, 0x23, 0x23, 0x23, 0x23,
    0x03
};

/*
 * DSP pre-DAC gain values from highest to lowest power (values obtained
 * from the reference driver.)
 */
static const uint8_t wpi_dsp_gain_2ghz[WPI_MAX_PWR_INDEX + 1] = {
    0x7f, 0x7f, 0x7f, 0x7f, 0x7d, 0x6e, 0x69, 0x62, 0x7d, 0x73, 0x6c,
    0x63, 0x77, 0x6f, 0x69, 0x61, 0x5c, 0x6a, 0x64, 0x78, 0x71, 0x6b,
    0x7d, 0x77, 0x70, 0x6a, 0x65, 0x61, 0x5b, 0x6b, 0x79, 0x73, 0x6d,
    0x7f, 0x79, 0x73, 0x6c, 0x66, 0x60, 0x5c, 0x6e, 0x68, 0x62, 0x74,
    0x7d, 0x77, 0x71, 0x6b, 0x65, 0x60, 0x71, 0x6a, 0x66, 0x5f, 0x71,
    0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66, 0x5f,
    0x71, 0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66,
    0x5f
};

static const uint8_t wpi_dsp_gain_5ghz[WPI_MAX_PWR_INDEX + 1] = {
    0x7f, 0x78, 0x72, 0x77, 0x65, 0x71, 0x66, 0x72, 0x67, 0x75, 0x6b,
    0x63, 0x5c, 0x6c, 0x7d, 0x76, 0x6d, 0x66, 0x60, 0x5a, 0x68, 0x62,
    0x5c, 0x76, 0x6f, 0x68, 0x7e, 0x79, 0x71, 0x69, 0x63, 0x76, 0x6f,
    0x68, 0x62, 0x74, 0x6d, 0x66, 0x62, 0x5d, 0x71, 0x6b, 0x63, 0x78,
    0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63,
    0x78, 0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63, 0x6b, 0x63, 0x78,
    0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63,
    0x78
};

/*
 * Power saving settings (values obtained from the reference driver.)
 */
#define WPI_NDTIMRANGES        2
#define WPI_NPOWERLEVELS    6
static const struct wpi_pmgt {
    uint32_t    rxtimeout;
    uint32_t    txtimeout;
    uint32_t    intval[5];
    int        skip_dtim;
} wpi_pmgt[WPI_NDTIMRANGES][WPI_NPOWERLEVELS] = {
    /* DTIM <= 10 */
    {
    {   0,   0, {  0,  0,  0,  0,  0 }, 0 },    /* CAM */
    { 200, 500, {  1,  2,  3,  4,  4 }, 0 },    /* PS level 1 */
    { 200, 300, {  2,  4,  6,  7,  7 }, 0 },    /* PS level 2 */
    {  50, 100, {  2,  6,  9,  9, 10 }, 0 },    /* PS level 3 */
    {  50,  25, {  2,  7,  9,  9, 10 }, 1 },    /* PS level 4 */
    {  25,  25, {  4,  7, 10, 10, 10 }, 1 }        /* PS level 5 */
    },
    /* DTIM >= 11 */
    {
    {   0,   0, {  0,  0,  0,  0,  0 }, 0 },    /* CAM */
    { 200, 500, {  1,  2,  3,  4, -1 }, 0 },    /* PS level 1 */
    { 200, 300, {  2,  4,  6,  7, -1 }, 0 },    /* PS level 2 */
    {  50, 100, {  2,  6,  9,  9, -1 }, 0 },    /* PS level 3 */
    {  50,  25, {  2,  7,  9,  9, -1 }, 0 },    /* PS level 4 */
    {  25,  25, {  4,  7, 10, 10, -1 }, 0 }        /* PS level 5 */
    }
};

/* Firmware errors. */
static const char * const wpi_fw_errmsg[] = {
    "OK",
    "FAIL",
    "BAD_PARAM",
    "BAD_CHECKSUM",
    "NMI_INTERRUPT",
    "SYSASSERT",
    "FATAL_ERROR"
};

#define WPI_READ(sc, reg)                        \
    bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg))

#define WPI_WRITE(sc, reg, val)                        \
    bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (val))

#define WPI_WRITE_REGION_4(sc, offset, datap, count)            \
    bus_space_write_region_4((sc)->sc_st, (sc)->sc_sh, (offset),    \
        (datap), (count))

#define WPI_SETBITS(sc, reg, mask)                    \
    WPI_WRITE(sc, reg, WPI_READ(sc, reg) | (mask))
 
#define WPI_CLRBITS(sc, reg, mask)                    \
    WPI_WRITE(sc, reg, WPI_READ(sc, reg) & ~(mask))

#define WPI_BARRIER_WRITE(sc)                        \
    bus_space_barrier((sc)->sc_st, (sc)->sc_sh, 0, (sc)->sc_sz,    \
        BUS_SPACE_BARRIER_WRITE)

#define WPI_BARRIER_READ_WRITE(sc)                    \
    bus_space_barrier((sc)->sc_st, (sc)->sc_sh, 0, (sc)->sc_sz,    \
        BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)
